From b61e6cb4e9f9d9c936ed60b1242c0b746a79d1cc Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk[kaf24]" Date: Sat, 30 Apr 2005 08:45:02 +0000 Subject: [PATCH] bitkeeper revision 1.1389.1.16 (4273458eyxEjHSppjkQyDsXHHxOY9Q) coredump.patch Extend libxc and gdb server to coredump a domain. Signed-off-by: Kip Macy --- .rootkeys | 3 + .../gdb/gdbserver/Makefile.in | 2 +- .../gdb/gdbserver/linux-xen-low.c | 40 +- .../gdb/gdbserver/server.c | 639 ++++++++++++++++++ tools/libxc/Makefile | 2 + tools/libxc/xc.h | 39 ++ tools/libxc/xc_core.c | 99 +++ tools/libxc/xc_ptrace.c | 9 +- tools/libxc/xc_ptrace_core.c | 287 ++++++++ tools/python/xen/lowlevel/xc/xc.c | 35 + 10 files changed, 1134 insertions(+), 21 deletions(-) create mode 100644 tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c create mode 100644 tools/libxc/xc_core.c create mode 100644 tools/libxc/xc_ptrace_core.c diff --git a/.rootkeys b/.rootkeys index cd12228470..e1444d613a 100644 --- a/.rootkeys +++ b/.rootkeys @@ -550,6 +550,7 @@ 423d3a7b2vJq86I8FbYm6up5BsCwfA tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.in 423d3a7bQPownmVb63qOoyq89ebBVA tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/configure.srv 423d3a7bHtqhyOgiRWhjWt-S-6wbYg tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c +4273458dYPghQKVnj_xu5-fC38CcOg tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c 423d3a7b2ENk2IskDZYZ98pe5NsvIA tools/gdb/gdb-6.2.1-xen-sparse/mkbuildtree 423d3a7buANO_q-kgxIRffUu7lMnUw tools/gdb/gdbbuild 41e2ff6dNPgvIrdIF6dC1azdex1U3A tools/ioemu/Makefile @@ -720,6 +721,7 @@ 3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/libxc/rpm.spec 3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/libxc/xc.h 3fbba6dbEVkVMX0JuDFzap9jeaucGA tools/libxc/xc_bvtsched.c +4273458dyF2_sKA6CFkNJQYb8eY2dA tools/libxc/xc_core.c 3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/libxc/xc_domain.c 40278d99BLsfUv3qxv0I8C1sClZ0ow tools/libxc/xc_elf.h 403e0977Bjsm_e82pwvl9VvaJxh8Gg tools/libxc/xc_evtchn.c @@ -735,6 +737,7 @@ 3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxc/xc_private.c 3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/xc_private.h 42337174PxyzzPk62raDiYCIsfStDg tools/libxc/xc_ptrace.c +4273458duzL--nsTfT6e_q6Kfij48g tools/libxc/xc_ptrace_core.c 41dde8b0pLfAKMs_L9Uri2hnzHiCRQ tools/libxc/xc_vmx_build.c 40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile 40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in index b6605f6698..93f177387c 100644 --- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in +++ b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/Makefile.in @@ -83,7 +83,7 @@ READLINE_DEP = $$(READLINE_DIR) # -I. for config files. # -I${srcdir} for our headers. # -I$(srcdir)/../regformats for regdef.h. -INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) +INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../regformats -I$(INCLUDE_DIR) -I../../../../libxc/ -I../../../../libxutil/ # M{H,T}_CFLAGS, if defined, has host- and target-dependent CFLAGS # from the config/ directory. diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c index c5cff23928..0e35f30294 100644 --- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c +++ b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c @@ -35,12 +35,11 @@ #include #include #include - +#include #define TRACE_ENTER /* printf("enter %s\n", __FUNCTION__) */ -#define ptrace xc_ptrace -long xc_ptrace(enum __ptrace_request request, ...); +long (*myptrace)(enum __ptrace_request, pid_t, long, long); +int (*myxcwait)(int domain, int *status, int options) ; -int waitdomain(int domain, int *status, int options); #define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */ #define DOMFLAGS_CRASHED (1<<1) /* Crashed domain; frozen for postmortem. */ @@ -61,6 +60,8 @@ static void linux_resume (struct thread_resume *resume_info); int debug_threads; int using_threads; +extern int isfile; + struct pending_signals { int signal; @@ -150,7 +151,7 @@ linux_attach (int domain) { struct process_info *new_process; current_domain = domain; - if (ptrace (PTRACE_ATTACH, domain, 0, 0) != 0) { + if (myptrace (PTRACE_ATTACH, domain, 0, 0) != 0) { fprintf (stderr, "Cannot attach to domain %d: %s (%d)\n", domain, strerror (errno), errno); fflush (stderr); @@ -173,7 +174,7 @@ linux_kill_one_process (struct inferior_list_entry *entry) { struct thread_info *thread = (struct thread_info *) entry; struct process_info *process = get_thread_process (thread); - ptrace (PTRACE_KILL, pid_of (process), 0, 0); + myptrace (PTRACE_KILL, pid_of (process), 0, 0); } @@ -190,7 +191,7 @@ linux_detach_one_process (struct inferior_list_entry *entry) struct thread_info *thread = (struct thread_info *) entry; struct process_info *process = get_thread_process (thread); - ptrace (PTRACE_DETACH, pid_of (process), 0, 0); + myptrace (PTRACE_DETACH, pid_of (process), 0, 0); } @@ -216,8 +217,7 @@ static unsigned char linux_wait (char *status) { int w; - TRACE_ENTER; - if (waitdomain(current_domain, &w, 0)) + if (myxcwait(current_domain, &w, 0)) return -1; if (w & (DOMFLAGS_CRASHED|DOMFLAGS_DYING)) { @@ -242,7 +242,7 @@ linux_resume (struct thread_resume *resume_info) expect_signal = resume_info->sig; for_each_inferior(&all_threads, regcache_invalidate_one); - ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, current_domain, 0, 0); + myptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, current_domain, 0, 0); } @@ -266,7 +266,7 @@ regsets_fetch_inferior_registers () } buf = malloc (regset->size); - res = ptrace (regset->get_request, inferior_pid, 0, buf); + res = myptrace (regset->get_request, inferior_pid, 0, (PTRACE_XFER_TYPE)buf); if (res < 0) { if (errno == EIO) @@ -318,7 +318,7 @@ regsets_store_inferior_registers () buf = malloc (regset->size); regset->fill_function (buf); - res = ptrace (regset->set_request, inferior_pid, 0, buf); + res = myptrace (regset->set_request, inferior_pid, 0, (PTRACE_XFER_TYPE)buf); if (res < 0) { if (errno == EIO) @@ -395,7 +395,7 @@ linux_read_memory (CORE_ADDR memaddr, char *myaddr, int len) for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0); + buffer[i] = myptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0); if (errno) return errno; } @@ -428,13 +428,13 @@ linux_write_memory (CORE_ADDR memaddr, const char *myaddr, int len) /* Fill start and end extra bytes of buffer with existing memory data. */ - buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid, + buffer[0] = myptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0); if (count > 1) { buffer[count - 1] - = ptrace (PTRACE_PEEKTEXT, inferior_pid, + = myptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE)), 0); @@ -448,7 +448,7 @@ linux_write_memory (CORE_ADDR memaddr, const char *myaddr, int len) for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - ptrace (PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]); + myptrace (PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]); if (errno) return errno; } @@ -545,4 +545,12 @@ initialize_low (void) the_low_target.breakpoint_len); init_registers (); linux_init_signals (); + if (isfile) { + myptrace = xc_ptrace_core; + myxcwait = xc_waitdomain_core; + } else { + myptrace = xc_ptrace; + myxcwait = xc_waitdomain; + } + } diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c new file mode 100644 index 0000000000..54f508a186 --- /dev/null +++ b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/server.c @@ -0,0 +1,639 @@ +/* Main code for remote server for GDB. + Copyright 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004 + Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "server.h" + +#include +#include +#include +#include +#include +#include + +int cont_thread; +int general_thread; +int step_thread; +int thread_from_wait; +int old_thread_from_wait; +int extended_protocol; +int server_waiting; +int isfile = 0; + +jmp_buf toplevel; + +/* The PID of the originally created or attached inferior. Used to + send signals to the process when GDB sends us an asynchronous interrupt + (user hitting Control-C in the client), and to wait for the child to exit + when no longer debugging it. */ + +int signal_pid; + +static unsigned char +start_inferior (char *argv[], char *statusptr) +{ + signal (SIGTTOU, SIG_DFL); + signal (SIGTTIN, SIG_DFL); + + signal_pid = create_inferior (argv[0], argv); + + fprintf (stderr, "Process %s created; pid = %d\n", argv[0], + signal_pid); + + signal (SIGTTOU, SIG_IGN); + signal (SIGTTIN, SIG_IGN); + tcsetpgrp (fileno (stderr), signal_pid); + + /* Wait till we are at 1st instruction in program, return signal number. */ + return mywait (statusptr, 0); +} + +static int +attach_inferior (int pid, char *statusptr, unsigned char *sigptr) +{ + /* myattach should return -1 if attaching is unsupported, + 0 if it succeeded, and call error() otherwise. */ + + if (myattach (pid) != 0) + return -1; + + fprintf (stderr, "Attached; pid = %d\n", pid); + + /* FIXME - It may be that we should get the SIGNAL_PID from the + attach function, so that it can be the main thread instead of + whichever we were told to attach to. */ + signal_pid = pid; + + *sigptr = mywait (statusptr, 0); + + return 0; +} + +extern int remote_debug; + +/* Handle all of the extended 'q' packets. */ +void +handle_query (char *own_buf) +{ + static struct inferior_list_entry *thread_ptr; + + if (strcmp ("qSymbol::", own_buf) == 0) + { + if (the_target->look_up_symbols != NULL) + (*the_target->look_up_symbols) (); + + strcpy (own_buf, "OK"); + return; + } + + if (strcmp ("qfThreadInfo", own_buf) == 0) + { + thread_ptr = all_threads.head; + sprintf (own_buf, "m%x", thread_ptr->id); + thread_ptr = thread_ptr->next; + return; + } + + if (strcmp ("qsThreadInfo", own_buf) == 0) + { + if (thread_ptr != NULL) + { + sprintf (own_buf, "m%x", thread_ptr->id); + thread_ptr = thread_ptr->next; + return; + } + else + { + sprintf (own_buf, "l"); + return; + } + } + + if (the_target->read_auxv != NULL + && strncmp ("qPart:auxv:read::", own_buf, 17) == 0) + { + char data[(PBUFSIZ - 1) / 2]; + CORE_ADDR ofs; + unsigned int len; + int n; + decode_m_packet (&own_buf[17], &ofs, &len); /* "OFS,LEN" */ + if (len > sizeof data) + len = sizeof data; + n = (*the_target->read_auxv) (ofs, data, len); + if (n == 0) + write_ok (own_buf); + else if (n < 0) + write_enn (own_buf); + else + convert_int_to_ascii (data, own_buf, n); + return; + } + + /* Otherwise we didn't know what packet it was. Say we didn't + understand it. */ + own_buf[0] = 0; +} + +/* Parse vCont packets. */ +void +handle_v_cont (char *own_buf, char *status, unsigned char *signal) +{ + char *p, *q; + int n = 0, i = 0; + struct thread_resume *resume_info, default_action; + + /* Count the number of semicolons in the packet. There should be one + for every action. */ + p = &own_buf[5]; + while (p) + { + n++; + p++; + p = strchr (p, ';'); + } + /* Allocate room for one extra action, for the default remain-stopped + behavior; if no default action is in the list, we'll need the extra + slot. */ + resume_info = malloc ((n + 1) * sizeof (resume_info[0])); + + default_action.thread = -1; + default_action.leave_stopped = 1; + default_action.step = 0; + default_action.sig = 0; + + p = &own_buf[5]; + i = 0; + while (*p) + { + p++; + + resume_info[i].leave_stopped = 0; + + if (p[0] == 's' || p[0] == 'S') + resume_info[i].step = 1; + else if (p[0] == 'c' || p[0] == 'C') + resume_info[i].step = 0; + else + goto err; + + if (p[0] == 'S' || p[0] == 'C') + { + int sig; + sig = strtol (p + 1, &q, 16); + if (p == q) + goto err; + p = q; + + if (!target_signal_to_host_p (sig)) + goto err; + resume_info[i].sig = target_signal_to_host (sig); + } + else + { + resume_info[i].sig = 0; + p = p + 1; + } + + if (p[0] == 0) + { + resume_info[i].thread = -1; + default_action = resume_info[i]; + + /* Note: we don't increment i here, we'll overwrite this entry + the next time through. */ + } + else if (p[0] == ':') + { + resume_info[i].thread = strtol (p + 1, &q, 16); + if (p == q) + goto err; + p = q; + if (p[0] != ';' && p[0] != 0) + goto err; + + i++; + } + } + + resume_info[i] = default_action; + + /* Still used in occasional places in the backend. */ + if (n == 1 && resume_info[0].thread != -1) + cont_thread = resume_info[0].thread; + else + cont_thread = -1; + set_desired_inferior (0); + + (*the_target->resume) (resume_info); + + free (resume_info); + + *signal = mywait (status, 1); + prepare_resume_reply (own_buf, *status, *signal); + return; + +err: + /* No other way to report an error... */ + strcpy (own_buf, ""); + free (resume_info); + return; +} + +/* Handle all of the extended 'v' packets. */ +void +handle_v_requests (char *own_buf, char *status, unsigned char *signal) +{ + if (strncmp (own_buf, "vCont;", 6) == 0) + { + handle_v_cont (own_buf, status, signal); + return; + } + + if (strncmp (own_buf, "vCont?", 6) == 0) + { + strcpy (own_buf, "vCont;c;C;s;S"); + return; + } + + /* Otherwise we didn't know what packet it was. Say we didn't + understand it. */ + own_buf[0] = 0; + return; +} + +void +myresume (int step, int sig) +{ + struct thread_resume resume_info[2]; + int n = 0; + + if (step || sig || cont_thread > 0) + { + resume_info[0].thread + = ((struct inferior_list_entry *) current_inferior)->id; + resume_info[0].step = step; + resume_info[0].sig = sig; + resume_info[0].leave_stopped = 0; + n++; + } + resume_info[n].thread = -1; + resume_info[n].step = 0; + resume_info[n].sig = 0; + resume_info[n].leave_stopped = (cont_thread > 0); + + (*the_target->resume) (resume_info); +} + +static int attached; + +static void +gdbserver_usage (void) +{ + error ("Usage:\tgdbserver COMM PROG [ARGS ...]\n" + "\tgdbserver COMM --attach PID\n" + "\tgdbserver COMM --file COREFILE\n" + "\n" + "COMM may either be a tty device (for serial debugging), or \n" + "HOST:PORT to listen for a TCP connection.\n"); +} + +int +main (int argc, char *argv[]) +{ + char ch, status, *own_buf, mem_buf[2000]; + int i = 0; + unsigned char signal; + unsigned int len; + CORE_ADDR mem_addr; + int bad_attach; + int pid; + char *arg_end; + + if (setjmp (toplevel)) + { + fprintf (stderr, "Exiting\n"); + exit (1); + } + + bad_attach = 0; + pid = 0; + attached = 0; + if (argc >= 3 && strcmp (argv[2], "--attach") == 0) + { + if (argc == 4 + && argv[3] != '\0' + && (pid = strtoul (argv[3], &arg_end, 10)) != 0 + && *arg_end == '\0') + { + ; + } + else + bad_attach = 1; + } + else if (argc >= 3 && strcmp (argv[2], "--file") == 0) + { + if (argc == 4 + && argv[3] != '\0') + { + if ((pid = open(argv[3], O_RDONLY)) <= 0) + bad_attach = 1; + else + isfile = 1; + } + else + bad_attach = 1; + } + + if (argc < 3 || bad_attach) + gdbserver_usage(); + + initialize_low (); + + own_buf = malloc (PBUFSIZ); + + if (pid == 0) + { + /* Wait till we are at first instruction in program. */ + signal = start_inferior (&argv[2], &status); + + /* We are now stopped at the first instruction of the target process */ + } + else + { + switch (attach_inferior (pid, &status, &signal)) + { + case -1: + error ("Attaching not supported on this target"); + break; + default: + attached = 1; + break; + } + } + + while (1) + { + remote_open (argv[1]); + + restart: + setjmp (toplevel); + while (getpkt (own_buf) > 0) + { + unsigned char sig; + i = 0; + ch = own_buf[i++]; + switch (ch) + { + case 'q': + handle_query (own_buf); + break; + case 'd': + remote_debug = !remote_debug; + break; + case 'D': + fprintf (stderr, "Detaching from inferior\n"); + detach_inferior (); + write_ok (own_buf); + putpkt (own_buf); + remote_close (); + + /* If we are attached, then we can exit. Otherwise, we need to + hang around doing nothing, until the child is gone. */ + if (!attached) + { + int status, ret; + + do { + ret = waitpid (signal_pid, &status, 0); + if (WIFEXITED (status) || WIFSIGNALED (status)) + break; + } while (ret != -1 || errno != ECHILD); + } + + exit (0); + + case '!': + if (attached == 0) + { + extended_protocol = 1; + prepare_resume_reply (own_buf, status, signal); + } + else + { + /* We can not use the extended protocol if we are + attached, because we can not restart the running + program. So return unrecognized. */ + own_buf[0] = '\0'; + } + break; + case '?': + prepare_resume_reply (own_buf, status, signal); + break; + case 'H': + switch (own_buf[1]) + { + case 'g': + general_thread = strtol (&own_buf[2], NULL, 16); + write_ok (own_buf); + set_desired_inferior (1); + break; + case 'c': + cont_thread = strtol (&own_buf[2], NULL, 16); + write_ok (own_buf); + break; + case 's': + step_thread = strtol (&own_buf[2], NULL, 16); + write_ok (own_buf); + break; + default: + /* Silently ignore it so that gdb can extend the protocol + without compatibility headaches. */ + own_buf[0] = '\0'; + break; + } + break; + case 'g': + set_desired_inferior (1); + registers_to_string (own_buf); + break; + case 'G': + set_desired_inferior (1); + registers_from_string (&own_buf[1]); + write_ok (own_buf); + break; + case 'm': + decode_m_packet (&own_buf[1], &mem_addr, &len); + if (read_inferior_memory (mem_addr, mem_buf, len) == 0) + convert_int_to_ascii (mem_buf, own_buf, len); + else + write_enn (own_buf); + break; + case 'M': + decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf); + if (write_inferior_memory (mem_addr, mem_buf, len) == 0) + write_ok (own_buf); + else + write_enn (own_buf); + break; + case 'C': + convert_ascii_to_int (own_buf + 1, &sig, 1); + if (target_signal_to_host_p (sig)) + signal = target_signal_to_host (sig); + else + signal = 0; + set_desired_inferior (0); + myresume (0, signal); + signal = mywait (&status, 1); + prepare_resume_reply (own_buf, status, signal); + break; + case 'S': + convert_ascii_to_int (own_buf + 1, &sig, 1); + if (target_signal_to_host_p (sig)) + signal = target_signal_to_host (sig); + else + signal = 0; + set_desired_inferior (0); + myresume (1, signal); + signal = mywait (&status, 1); + prepare_resume_reply (own_buf, status, signal); + break; + case 'c': + set_desired_inferior (0); + myresume (0, 0); + signal = mywait (&status, 1); + prepare_resume_reply (own_buf, status, signal); + break; + case 's': + set_desired_inferior (0); + myresume (1, 0); + signal = mywait (&status, 1); + prepare_resume_reply (own_buf, status, signal); + break; + case 'k': + fprintf (stderr, "Killing inferior\n"); + kill_inferior (); + /* When using the extended protocol, we start up a new + debugging session. The traditional protocol will + exit instead. */ + if (extended_protocol) + { + write_ok (own_buf); + fprintf (stderr, "GDBserver restarting\n"); + + /* Wait till we are at 1st instruction in prog. */ + signal = start_inferior (&argv[2], &status); + goto restart; + break; + } + else + { + exit (0); + break; + } + case 'T': + if (mythread_alive (strtol (&own_buf[1], NULL, 16))) + write_ok (own_buf); + else + write_enn (own_buf); + break; + case 'R': + /* Restarting the inferior is only supported in the + extended protocol. */ + if (extended_protocol) + { + kill_inferior (); + write_ok (own_buf); + fprintf (stderr, "GDBserver restarting\n"); + + /* Wait till we are at 1st instruction in prog. */ + signal = start_inferior (&argv[2], &status); + goto restart; + break; + } + else + { + /* It is a request we don't understand. Respond with an + empty packet so that gdb knows that we don't support this + request. */ + own_buf[0] = '\0'; + break; + } + case 'v': + /* Extended (long) request. */ + handle_v_requests (own_buf, &status, &signal); + break; + default: + /* It is a request we don't understand. Respond with an + empty packet so that gdb knows that we don't support this + request. */ + own_buf[0] = '\0'; + break; + } + + putpkt (own_buf); + + if (status == 'W') + fprintf (stderr, + "\nChild exited with status %d\n", signal); + if (status == 'X') + fprintf (stderr, "\nChild terminated with signal = 0x%x\n", + signal); + if (status == 'W' || status == 'X') + { + if (extended_protocol) + { + fprintf (stderr, "Killing inferior\n"); + kill_inferior (); + write_ok (own_buf); + fprintf (stderr, "GDBserver restarting\n"); + + /* Wait till we are at 1st instruction in prog. */ + signal = start_inferior (&argv[2], &status); + goto restart; + break; + } + else + { + fprintf (stderr, "GDBserver exiting\n"); + exit (0); + } + } + } + + /* We come here when getpkt fails. + + For the extended remote protocol we exit (and this is the only + way we gracefully exit!). + + For the traditional remote protocol close the connection, + and re-open it at the top of the loop. */ + if (extended_protocol) + { + remote_close (); + exit (0); + } + else + { + fprintf (stderr, "Remote side has terminated connection. " + "GDBserver will reopen the connection.\n"); + remote_close (); + } + } +} diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index eea5218754..e458444bb0 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -17,6 +17,7 @@ INCLUDES += -I $(XEN_LIBXUTIL) SRCS := SRCS += xc_bvtsched.c +SRCS += xc_core.c SRCS += xc_domain.c SRCS += xc_evtchn.c SRCS += xc_gnttab.c @@ -29,6 +30,7 @@ SRCS += xc_misc.c SRCS += xc_physdev.c SRCS += xc_private.c SRCS += xc_ptrace.c +SRCS += xc_ptrace_core.c SRCS += xc_vmx_build.c CFLAGS += -Wall diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h index 9eac0a7a18..80a3914208 100644 --- a/tools/libxc/xc.h +++ b/tools/libxc/xc.h @@ -20,6 +20,7 @@ typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; +#include #include #include #include @@ -71,6 +72,38 @@ int xc_interface_open(void); */ int xc_interface_close(int xc_handle); +/* + * DOMAIN DEBUGGING FUNCTIONS + */ + +typedef struct xc_core_header { + unsigned int xch_magic; + unsigned int xch_nr_vcpus; + unsigned int xch_nr_pages; + unsigned int xch_ctxt_offset; + unsigned int xch_index_offset; + unsigned int xch_pages_offset; +} xc_core_header_t; + + +long xc_ptrace(enum __ptrace_request request, + pid_t pid, + long addr, + long data); + +long xc_ptrace_core(enum __ptrace_request request, + pid_t pid, + long addr, + long data); + +int xc_waitdomain(int domain, + int *status, + int options); + +int xc_waitdomain_core(int domain, + int *status, + int options); + /* * DOMAIN MANAGEMENT FUNCTIONS */ @@ -94,6 +127,12 @@ int xc_domain_create(int xc_handle, float cpu_weight, u32 *pdomid); + +int xc_domain_dumpcore(int xc_handle, + u32 domid, + const char *corename); + + /** * This function pauses a domain. A paused domain still exists in memory * however it does not receive any timeslices from the hypervisor. diff --git a/tools/libxc/xc_core.c b/tools/libxc/xc_core.c new file mode 100644 index 0000000000..84ef16bf37 --- /dev/null +++ b/tools/libxc/xc_core.c @@ -0,0 +1,99 @@ +#include "xc_private.h" +#define ELFSIZE 32 +#include "xc_elf.h" +#include +#include + +/* number of pages to write at a time */ +#define DUMP_INCREMENT 4 * 1024 +#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) +static int +copy_from_domain_page(int xc_handle, + u32 domid, + unsigned long *page_array, + unsigned long src_pfn, + void *dst_page) +{ + void *vaddr = xc_map_foreign_range( + xc_handle, domid, PAGE_SIZE, PROT_READ, page_array[src_pfn]); + if ( vaddr == NULL ) + return -1; + memcpy(dst_page, vaddr, PAGE_SIZE); + munmap(vaddr, PAGE_SIZE); + return 0; +} + +int +xc_domain_dumpcore(int xc_handle, + u32 domid, + const char *corename) +{ + vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt; + unsigned long nr_pages; + unsigned long *page_array; + xc_domaininfo_t st_info, *info = &st_info; + int i, dump_fd; + char *dump_mem, *dump_mem_start = NULL; + struct xc_core_header header; + + if ((dump_fd = open(corename, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)) < 0) { + PERROR("Could not open corefile %s: %s", corename, strerror(errno)); + goto error_out; + } + + if ((dump_mem_start = malloc(DUMP_INCREMENT*PAGE_SIZE)) == 0) { + PERROR("Could not allocate dump_mem"); + goto error_out; + } + + if (xc_domain_getfullinfo(xc_handle, domid, 0/* XXX hardcode */, info, ctxt)) { + PERROR("Could not get full info for domain"); + goto error_out; + } + + nr_pages = info->tot_pages; + header.xch_magic = 0xF00FEBED; + header.xch_nr_vcpus = 1; /* no interface to query at the moment */ + header.xch_nr_pages = nr_pages; + header.xch_ctxt_offset = sizeof(struct xc_core_header); + header.xch_index_offset = sizeof(struct xc_core_header) + + sizeof(vcpu_guest_context_t); + header.xch_pages_offset = round_pgup(sizeof(struct xc_core_header) + + sizeof(vcpu_guest_context_t) + nr_pages * sizeof(unsigned long)); + + write(dump_fd, &header, sizeof(struct xc_core_header)); + write(dump_fd, ctxt, sizeof(st_ctxt)); + + if ((page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL) { + printf("Could not allocate memory\n"); + goto error_out; + } + if (xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages) { + printf("Could not get the page frame list\n"); + goto error_out; + } + write(dump_fd, page_array, nr_pages * sizeof(unsigned long)); + lseek(dump_fd, header.xch_pages_offset, SEEK_SET); + for (dump_mem = dump_mem_start, i = 0; i < nr_pages; i++) { + copy_from_domain_page(xc_handle, domid, page_array, i, dump_mem); + dump_mem += PAGE_SIZE; + if (((i + 1) % DUMP_INCREMENT == 0) || (i + 1) == nr_pages) { + if (write(dump_fd, dump_mem_start, dump_mem - dump_mem_start) < + dump_mem - dump_mem_start) { + PERROR("Partial write, file system full?"); + goto error_out; + } + dump_mem = dump_mem_start; + } + } + + close(dump_fd); + free(dump_mem_start); + return 0; + error_out: + if (dump_fd) + close(dump_fd); + if (dump_mem_start) + free(dump_mem_start); + return -1; +} diff --git a/tools/libxc/xc_ptrace.c b/tools/libxc/xc_ptrace.c index df05b59d4e..287680573f 100644 --- a/tools/libxc/xc_ptrace.c +++ b/tools/libxc/xc_ptrace.c @@ -17,8 +17,7 @@ * ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); */ -long xc_ptrace(enum __ptrace_request request, - pid_t pid, void *addr, void *data); + int waitdomain(int domain, int *status, int options); char * ptrace_names[] = { @@ -218,7 +217,7 @@ map_domain_va(unsigned long domid, int cpu, void * guest_va, int perm) } int -waitdomain(int domain, int *status, int options) +xc_waitdomain(int domain, int *status, int options) { dom0_op_t op; int retval; @@ -260,7 +259,7 @@ waitdomain(int domain, int *status, int options) } long -xc_ptrace(enum __ptrace_request request, pid_t domid, void *addr, void *data) +xc_ptrace(enum __ptrace_request request, pid_t domid, long eaddr, long edata) { dom0_op_t op; int status = 0; @@ -268,6 +267,8 @@ xc_ptrace(enum __ptrace_request request, pid_t domid, void *addr, void *data) long retval = 0; unsigned long *guest_va; int cpu = VCPU; + void *addr = (char *)eaddr; + void *data = (char *)edata; op.interface_version = DOM0_INTERFACE_VERSION; diff --git a/tools/libxc/xc_ptrace_core.c b/tools/libxc/xc_ptrace_core.c new file mode 100644 index 0000000000..87b88edf3d --- /dev/null +++ b/tools/libxc/xc_ptrace_core.c @@ -0,0 +1,287 @@ +#include +#include +#include "xc_private.h" +#include +#include + + +#define BSD_PAGE_MASK (PAGE_SIZE-1) +#define PG_FRAME (~((unsigned long)BSD_PAGE_MASK) +#define PDRSHIFT 22 +#define PSL_T 0x00000100 /* trace enable bit */ + +#define VCPU 0 /* XXX */ + +/* + * long + * ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); + */ + + +struct gdb_regs { + long ebx; /* 0 */ + long ecx; /* 4 */ + long edx; /* 8 */ + long esi; /* 12 */ + long edi; /* 16 */ + long ebp; /* 20 */ + long eax; /* 24 */ + int xds; /* 28 */ + int xes; /* 32 */ + int xfs; /* 36 */ + int xgs; /* 40 */ + long orig_eax; /* 44 */ + long eip; /* 48 */ + int xcs; /* 52 */ + long eflags; /* 56 */ + long esp; /* 60 */ + int xss; /* 64 */ +}; + +#define printval(x) printf("%s = %lx\n", #x, (long)x); +#define SET_PT_REGS(pt, xc) \ +{ \ + pt.ebx = xc.ebx; \ + pt.ecx = xc.ecx; \ + pt.edx = xc.edx; \ + pt.esi = xc.esi; \ + pt.edi = xc.edi; \ + pt.ebp = xc.ebp; \ + pt.eax = xc.eax; \ + pt.eip = xc.eip; \ + pt.xcs = xc.cs; \ + pt.eflags = xc.eflags; \ + pt.esp = xc.esp; \ + pt.xss = xc.ss; \ + pt.xes = xc.es; \ + pt.xds = xc.ds; \ + pt.xfs = xc.fs; \ + pt.xgs = xc.gs; \ +} + +#define SET_XC_REGS(pt, xc) \ +{ \ + xc.ebx = pt->ebx; \ + xc.ecx = pt->ecx; \ + xc.edx = pt->edx; \ + xc.esi = pt->esi; \ + xc.edi = pt->edi; \ + xc.ebp = pt->ebp; \ + xc.eax = pt->eax; \ + xc.eip = pt->eip; \ + xc.cs = pt->xcs; \ + xc.eflags = pt->eflags; \ + xc.esp = pt->esp; \ + xc.ss = pt->xss; \ + xc.es = pt->xes; \ + xc.ds = pt->xds; \ + xc.fs = pt->xfs; \ + xc.gs = pt->xgs; \ +} + + +#define vtopdi(va) ((va) >> PDRSHIFT) +#define vtopti(va) (((va) >> PAGE_SHIFT) & 0x3ff) + +/* XXX application state */ + + +static long nr_pages = 0; +static unsigned long *p2m_array = NULL; +static unsigned long *m2p_array = NULL; +static unsigned long pages_offset; +static unsigned long cr3[MAX_VIRT_CPUS]; +static vcpu_guest_context_t ctxt[MAX_VIRT_CPUS]; + +/* --------------------- */ + +static unsigned long +map_mtop_offset(unsigned long ma) +{ + return pages_offset + (m2p_array[ma >> PAGE_SHIFT] << PAGE_SHIFT); +} + + +static void * +map_domain_va(unsigned long domfd, int cpu, void * guest_va) +{ + unsigned long pde, page; + unsigned long va = (unsigned long)guest_va; + + static unsigned long cr3_phys[MAX_VIRT_CPUS]; + static unsigned long *cr3_virt[MAX_VIRT_CPUS]; + static unsigned long pde_phys[MAX_VIRT_CPUS]; + static unsigned long *pde_virt[MAX_VIRT_CPUS]; + static unsigned long page_phys[MAX_VIRT_CPUS]; + static unsigned long *page_virt[MAX_VIRT_CPUS]; + + if (cr3[cpu] != cr3_phys[cpu]) + { + cr3_phys[cpu] = cr3[cpu]; + if (cr3_virt[cpu]) + munmap(cr3_virt[cpu], PAGE_SIZE); + if ((cr3_virt[cpu] = mmap(NULL, PAGE_SIZE, PROT_READ, + MAP_PRIVATE, domfd, map_mtop_offset(cr3_phys[cpu]))) == + (unsigned long*)0xffffffff) + { + perror("mmap failed"); + goto error_out; + } + } + if ((pde = cr3_virt[cpu][vtopdi(va)]) == 0) /* logical address */ + goto error_out; + if (ctxt[cpu].flags & VGCF_VMX_GUEST) + pde = p2m_array[pde >> PAGE_SHIFT] << PAGE_SHIFT; + if (pde != pde_phys[cpu]) + { + pde_phys[cpu] = pde; + if (pde_virt[cpu]) + munmap(pde_virt[cpu], PAGE_SIZE); + if ((pde_virt[cpu] = mmap(NULL, PAGE_SIZE, PROT_READ, + MAP_PRIVATE, domfd, map_mtop_offset(pde_phys[cpu]))) == NULL) + goto error_out; + } + if ((page = pde_virt[cpu][vtopti(va)]) == 0) /* logical address */ + goto error_out; + if (ctxt[cpu].flags & VGCF_VMX_GUEST) + page = p2m_array[page >> PAGE_SHIFT] << PAGE_SHIFT; + if (page != page_phys[cpu]) + { + page_phys[cpu] = page; + if (page_virt[cpu]) + munmap(page_virt[cpu], PAGE_SIZE); + if ((page_virt[cpu] = mmap(NULL, PAGE_SIZE, PROT_READ, + MAP_PRIVATE, domfd, map_mtop_offset(page_phys[cpu]))) == NULL) { + printf("cr3 %lx pde %lx page %lx pti %lx\n", cr3[cpu], pde, page, vtopti(va)); + page_phys[cpu] = 0; + goto error_out; + } + } + return (void *)(((unsigned long)page_virt[cpu]) | (va & BSD_PAGE_MASK)); + + error_out: + return 0; +} + +int +xc_waitdomain_core(int domfd, int *status, int options) +{ + int retval = -1; + int nr_vcpus; + int i; + xc_core_header_t header; + + if (nr_pages == 0) { + + if (read(domfd, &header, sizeof(header)) != sizeof(header)) + return -1; + + nr_pages = header.xch_nr_pages; + nr_vcpus = header.xch_nr_vcpus; + pages_offset = header.xch_pages_offset; + + if (read(domfd, ctxt, sizeof(vcpu_guest_context_t)*nr_vcpus) != + sizeof(vcpu_guest_context_t)*nr_vcpus) + return -1; + + for (i = 0; i < nr_vcpus; i++) { + cr3[i] = ctxt[i].pt_base; + } + if ((p2m_array = malloc(nr_pages * sizeof(unsigned long))) == NULL) { + printf("Could not allocate p2m_array\n"); + goto error_out; + } + if (read(domfd, p2m_array, sizeof(unsigned long)*nr_pages) != + sizeof(unsigned long)*nr_pages) + return -1; + + if ((m2p_array = malloc((1<<20) * sizeof(unsigned long))) == NULL) { + printf("Could not allocate m2p array\n"); + goto error_out; + } + bzero(m2p_array, sizeof(unsigned long)* 1 << 20); + + for (i = 0; i < nr_pages; i++) { + m2p_array[p2m_array[i]] = i; + } + + } + retval = 0; + error_out: + return retval; + +} + +long +xc_ptrace_core(enum __ptrace_request request, int domfd, long eaddr, long edata) +{ + int status = 0; + struct gdb_regs pt; + long retval = 0; + unsigned long *guest_va; + int cpu = VCPU; + void *addr = (char *)eaddr; + void *data = (char *)edata; + +#if 0 + printf("%20s %d, %p, %p \n", ptrace_names[request], domid, addr, data); +#endif + switch (request) { + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + if ((guest_va = (unsigned long *)map_domain_va(domfd, cpu, addr)) == NULL) { + status = EFAULT; + goto error_out; + } + + retval = *guest_va; + break; + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + if ((guest_va = (unsigned long *)map_domain_va(domfd, cpu, addr)) == NULL) { + status = EFAULT; + goto error_out; + } + *guest_va = (unsigned long)data; + break; + case PTRACE_GETREGS: + case PTRACE_GETFPREGS: + case PTRACE_GETFPXREGS: + if (request == PTRACE_GETREGS) { + SET_PT_REGS(pt, ctxt[cpu].user_regs); + memcpy(data, &pt, sizeof(elf_gregset_t)); + } else if (request == PTRACE_GETFPREGS) + memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt)); + else /*if (request == PTRACE_GETFPXREGS)*/ + memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt)); + break; + case PTRACE_ATTACH: + retval = 0; + break; + case PTRACE_SETREGS: + case PTRACE_SINGLESTEP: + case PTRACE_CONT: + case PTRACE_DETACH: + case PTRACE_SETFPREGS: + case PTRACE_SETFPXREGS: + case PTRACE_PEEKUSER: + case PTRACE_POKEUSER: + case PTRACE_SYSCALL: + case PTRACE_KILL: +#ifdef DEBUG + printf("unsupported xc_ptrace request %s\n", ptrace_names[request]); +#endif + status = ENOSYS; + break; + case PTRACE_TRACEME: + printf("PTRACE_TRACEME is an invalid request under Xen\n"); + status = EINVAL; + } + + if (status) { + errno = status; + retval = -1; + } + error_out: + return retval; +} diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index a474c4a888..5b76a20f43 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -36,6 +36,33 @@ typedef struct { * Definitions for the 'xc' object type. */ +static PyObject *pyxc_domain_dumpcore(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + char *corefile; + + static char *kwd_list[] = { "dom", "corefile", NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list, &dom, &corefile) ) + goto exit; + + if ( (corefile == NULL) || (corefile[0] == '\0') ) + goto exit; + + if ( xc_domain_dumpcore(xc->xc_handle, dom, corefile) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; + + exit: + return NULL; +} + static PyObject *pyxc_domain_create(PyObject *self, PyObject *args, PyObject *kwds) @@ -854,6 +881,14 @@ static PyMethodDef pyxc_methods[] = { " mem_kb [int, 0]: Memory allocation, in kilobytes.\n" "Returns: [int] new domain identifier; -1 on error.\n" }, + { "domain_dumpcore", + (PyCFunction)pyxc_domain_dumpcore, + METH_VARARGS | METH_KEYWORDS, "\n" + "dump core of a domain.\n" + " dom [int]: Identifier of domain to be paused.\n\n" + " corefile [string]: Name of corefile to be created.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_pause", (PyCFunction)pyxc_domain_pause, METH_VARARGS | METH_KEYWORDS, "\n" -- 2.30.2